﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using PMRC.API.Context;
using PMRC.API.Domain;
using PMRC.API.Model.View;
using PMRC.API.Server.Interface;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using static Dm.net.buffer.ByteArrayBuffer;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace PMRC.API.Controllers
{
    /// <summary>
    /// 认证管理
    /// </summary>
    [Route("api/auth")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly ILogger<AccountController> _logger;
        private readonly IConfiguration _configuration;
        private readonly ISmsService _smsService;
        private readonly DbContext _db;
        public AccountController(
            ILogger<AccountController> logger,
            IConfiguration configuration,
            ISmsService smsService,
            DbContext db
            )
        {
            _logger = logger;
            _configuration = configuration;
            _smsService = smsService;
            _db = db;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="loginView"></param>
        /// <returns></returns>
        [HttpPost("signin")]
        public async Task<IActionResult> SignIn([FromForm] LoginViewModel loginView)
        {
            try
            {
                //判断验证码是否超过5分钟
                var verifCode = await _db.Queryable<SysVerificationCode>().OrderByDescending(x => x.SentTime).Where(x => x.PhoneNumber == loginView.PhoneNumbe && x.Code == loginView.Code).FirstAsync();
                if (verifCode == null)
                {
                    return Ok(new
                    {
                        Code = 1,
                        Message = "验证码不正确!"
                    });
                }
                if (verifCode.SentTime.AddMinutes(5) <= DateTime.Now)
                {
                    return Ok(new
                    {
                        Code = 1,
                        Message = "验证码已过期!"
                    });
                }
                var userInfo = await _db.Queryable<SysUser>().Where(x => x.PhoneNumber == loginView.PhoneNumbe).FirstAsync();

                var token = await GenerateTokenAsync(userInfo);
                var expirationInHours = int.Parse(_configuration["JwtConfig:ExpirationInHours"]);
                return Ok(new
                {
                    Code = 0,
                    Token = token,
                    ExpireTime = DateTime.Now.AddHours(expirationInHours).ToString("yyyy-MM-dd HH:mm:ss"),
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 发送验证码
        /// </summary>
        /// <param name="sendCode"></param>
        /// <returns></returns>
        [HttpPost("sendcode")]
        public async Task<IActionResult> SendCodeAsync([FromForm] SendCodeViewModel sendCode)
        {
            try
            {
                //判断当前账号2分钟内是否发送过验证码
                var verifCode = await _db.Queryable<SysVerificationCode>().OrderByDescending(x => x.SentTime).Where(x => x.PhoneNumber == sendCode.PhoneNumbe).FirstAsync();
                if (verifCode != null && verifCode.SentTime.AddMinutes(2) > DateTime.Now)
                {
                    return Ok(new
                    {
                        Code = 1,
                        Message = "验证码已发送，请稍后再试等。"
                    });
                }
                var code = GenerateVerificationCode(4);
                var isVictory = await _smsService.SendVerificationCodeAsync(sendCode.PhoneNumbe, code);
                if (isVictory)
                {
                    var data = new SysVerificationCode
                    {
                        Code = code,
                        PhoneNumber = sendCode.PhoneNumbe,
                        SentTime = DateTime.Now
                    };
                    await _db.Insertable(data).ExecuteCommandAsync();
                    return Ok(new
                    {
                        Code = 0
                    });
                }
                else
                {
                    return Ok(new
                    {
                        Code = 2,
                        Message = "系统错误！"
                    });
                }

            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 随机生成验证码
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private string GenerateVerificationCode(int length)
        {

            int min = (int)Math.Pow(10, length - 1);
            int max = (int)Math.Pow(10, length) - 1;

            Random random = new Random();
            int code = random.Next(min, max);

            return code.ToString();
        }

        /// <summary>
        /// 生成token
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task<string> GenerateTokenAsync(SysUser user)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes(_configuration["JwtConfig:SecretKey"]);
            var issuer = _configuration["JwtConfig:Issuer"];
            var audience = _configuration["JwtConfig:Audience"];
            var expirationInHours = int.Parse(_configuration["JwtConfig:ExpirationInHours"]);

            //var roleIds = await _db.Queryable<SysUserRole>().Where(x => x.UserId == user.Id).Select(x => x.RoleId).ToListAsync();

            //var roles = await _db.Queryable<SysRole>().Where(x => roleIds.Contains(x.Id)).ToListAsync();

            //var roleNames = roles.Select(x => x.Name).ToList();

            var claimsIdentity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.NameIdentifier,user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.NickName)
            });
            //foreach (var roleName in roleNames)
            //{
            //    claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, roleName));
            //}
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = claimsIdentity,
                Expires = DateTime.Now.AddHours(expirationInHours),
                Issuer = issuer,
                Audience = audience,
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }

    }
}
